package com.metel.mservice.common.utils;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

import org.apache.commons.codec.binary.Base32;


public class BuddyidCipherUtil {

	private static final String ENC_KEY = "AnNyoungChat+On"; 
	private static final String BUDDYID_PREFIX = "buddy-"; 
	private static final String ENCRYPT_PATTERN = "[0-9]+"; 
	private static final int NUMBERCHECK = 19; 
	
	private static Pattern[] DANGEROUS_PATTERN_AT_RESPONSE_BODY = new Pattern[] {
		Pattern.compile("uid=[0-9a-z\\-]+&imei=web&?"),
		Pattern.compile("uid=[0-9a-z\\-]+&imei=null&?")
	};
	
	private static Pattern[] PRIVACY_PATTERN_AT_RESPONSE_BODY= new Pattern[] {
		Pattern.compile("\"showphonenumber\"\\s*:\\s*true,[^}]*\"orgnum\"\\s*:\\s*\"(" + ENCRYPT_PATTERN + ")\""),
		Pattern.compile("\"orgnum\"\\s*:\\s*\"(" + ENCRYPT_PATTERN + ")\",[^}]*\"showphonenumber\"\\s*:\\s*true")
	};

	private static Pattern[] BUDDYID_PATTERN_AT_RESPONSE_BODY= new Pattern[] {
		  Pattern.compile("\"(id|buddyid|msisdn|orgnum|sender|member|chaton_id|app_chaton_id)\"\\s*:\\s*(\"\\+*" + ENCRYPT_PATTERN + "\")"),
		  Pattern.compile("\"(msisdn|chatmembers|receiver|groupmemeberlist|recommendeeUserID|ignorelist)\"\\s*:\\s*(\\[[" + ENCRYPT_PATTERN + "\\s*,\"]+\\])"),
		  Pattern.compile("\"(resultmsg)\"\\s*:(.*\\[[" + ENCRYPT_PATTERN + "\\s*,\"]+\\])"),
		  Pattern.compile("\"(profileimageurl)\"\\s*:(\"([\\p{Alnum}]+)://([a-z0-9.-~]+)/buddy/([a-z0-9.\\-&/%=?:@#$(),.+;~\\_]+)\")")
	};
	

	public static String changeMsisdn(String str) throws Exception {
		return encryptBuddyid(str);
	}
	
	/**
	 * API 서버에서 전달받은 응답 Body의 버디아이디 암호화 
	 */
	public static String changeResponse(String str) throws Exception {
		for(Pattern ptrn : DANGEROUS_PATTERN_AT_RESPONSE_BODY) {
			str = removeDangerous(ptrn, str);
		}
		for(Pattern ptrn : PRIVACY_PATTERN_AT_RESPONSE_BODY) {
			str = appendPhonenumberOfPermission(ptrn, str);
		}
		for(Pattern ptrn : BUDDYID_PATTERN_AT_RESPONSE_BODY) {
			str = encryptJSONString(ptrn, str);
		}
		return str;
	}
	
	private static Pattern[] BUDDYID_PATTERN_AT_REQUEST_BODY = new Pattern[] {
		Pattern.compile(BUDDYID_PREFIX + "([0-9a-zA-Z]+)")
	};
	
	/**
	 * 클라이언트에서 전달받은 요청 Body의 버디아이디 복호화 
	 */
	public static String changeRequest(String str) throws Exception {
		for(Pattern ptrn : BUDDYID_PATTERN_AT_REQUEST_BODY) {
			str = decryptBuddyid(ptrn, str);
		}
		return str;
	}
	
	private static String removeDangerous(Pattern ptrn, String str) throws Exception {
		if(str == null) { return ""; }
		Matcher m = ptrn.matcher(str);
		StringBuffer sb = new StringBuffer();
		while(m.find()) {
			m.appendReplacement(sb, "");
		}
		m.appendTail(sb);
		return sb.toString();
	}
	
	private static String appendPhonenumberOfPermission(Pattern ptrn, String str) throws Exception {
		if(str == null) { return ""; }
		Matcher m = ptrn.matcher(str);
		StringBuffer sb = new StringBuffer();
		while(m.find()) {
			m.appendReplacement(sb, m.group(0) + ",\"pb4web\":\"" + m.group(1)+ "\"");
		}
		m.appendTail(sb);
		return sb.toString();
	}
	
	private static String encryptJSONString(Pattern ptrn, String str) throws Exception {
		if(str == null) { return ""; }
		Matcher m = ptrn.matcher(str);
		StringBuffer sb = new StringBuffer();
		while(m.find()) {
			m.appendReplacement(sb, "\"" + m.group(1) + "\":" + encryptBuddyid(m.group(2)));
		}
		m.appendTail(sb);
		return sb.toString();
	}
	
	private static String encryptBuddyid(String str) throws Exception {
		if(str == null) { return ""; }
		StringBuffer sb = new StringBuffer();
		Matcher m = Pattern.compile(ENCRYPT_PATTERN).matcher(str);
		while(m.find()) {
			if(NUMBERCHECK > m.group(0).length() && !"0".equals(m.group(0).substring(0, 1)))
				m.appendReplacement(sb, BUDDYID_PREFIX + encryptString(m.group(0)));
		}
		m.appendTail(sb);
		return sb.toString();
		
	}
	
	private static String decryptBuddyid(Pattern ptrn, String str) throws Exception {
		if(str == null) { return ""; }
		Matcher m = ptrn.matcher(str);
		StringBuffer sb = new StringBuffer();
		while(m.find()) {
			m.appendReplacement(sb, decryptString(m.group(1)));
		}
		m.appendTail(sb);
		return sb.toString();
	}
	
	private static Pattern CHARACTER_ENCRYPT_MORE = Pattern.compile("([CHATONWEB])");
	private static String encryptString(String str) throws Exception {
		if(str == null) { return ""; }
		Cipher cipher = getCipher(Cipher.ENCRYPT_MODE);
		byte[] encrypted = cipher.doFinal(str.getBytes());
		byte[] encoded = new Base32().encode(encrypted);
		Matcher m = CHARACTER_ENCRYPT_MORE.matcher(new String(encoded));
		StringBuffer sb = new StringBuffer();
		while(m.find()) {
			m.appendReplacement(sb, m.group(1).toLowerCase());
		}
		m.appendTail(sb);
		return sb.toString().replaceAll("=", "").replaceAll("/", "C");
	}
	
	private static String decryptString(String str) throws Exception {
		if(str == null) { return ""; }
		while(str.length() % 4 != 0) {str += "=";}
		byte[] decoded = new Base32().decode(str.replaceAll("C", "/").toUpperCase().getBytes());
		Cipher cipher = getCipher(Cipher.DECRYPT_MODE);
		byte[] decrypted = cipher.doFinal(decoded);
		return new String(decrypted);
	}
	
	private static Cipher getCipher(int mode) throws Exception {
		DESKeySpec keySpec = new DESKeySpec(ENC_KEY.getBytes());
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
		SecretKey key = keyFactory.generateSecret(keySpec);
		
		Cipher cipher = Cipher.getInstance("DES");
		cipher.init(mode, key);
		return cipher;
	}
	
	

}
